<!DOCTYPE HTML>
<!--generated with sswg-->
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
    <title> ursina engine documentation</title>
    <link rel="stylesheet" href="sswg.css">
    <link rel="stylesheet" href="style.css">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<div style="max-width:1200px; margin:auto;">
<div style="text-align:left;">
<br>
<a href="index.html"><img src="ursina_logo_wireframe.webp" style="width:50px; height:auto; margin-right:10px;"/></a> <a href=" installation.html" class="button">Download</a> <a href=" documentation.html" class="button">Documentation</a> <a href=" api_reference_v8_2_0/index.html" class="button">API Reference</a> <a href=" samples.html" class="button">Samples</a> <a href=" asset_store.html" class="button">Asset Store</a> <a href=" donate.html" class="button">Donate</a><br>
<h1 id="Pong">
Pong
</h1><a href="https://github.com/pokepetter/ursina/blob/master/samples/pong.py">https://github.com/pokepetter/ursina/blob/master/samples/pong.py</a><br>
<br>
<img src="icons/pong.jpg"></img> <br>
<code_block id="code_block_0"><button class="copy_code_button" onclick="copy_to_clipboard(code_block_0)">copy</button><purple>from</purple> ursina <purple>import</purple> *

app = Ursina()

window.color = color.black
camera.orthographic = True
camera.fov = <yellow>1</yellow>

left_paddle = <olive>Entity</olive>(<olive>scale</olive>=(<yellow>1</yellow>/<yellow>3</yellow><yellow>2</yellow>,<yellow>6</yellow>/<yellow>3</yellow><yellow>2</yellow>), x=-.<yellow>7</yellow><yellow>5</yellow>, <olive>model</olive>=<green>'quad'</green>, <olive>origin_x</olive>=.<yellow>5</yellow>, <olive>collider</olive>=<green>'box'</green>)
right_paddle = duplicate(left_paddle, x=left_paddle.x*-<yellow>1</yellow>, rotation_<olive>z</olive>=left_paddle.rotation_z+<yellow>1</yellow><yellow>8</yellow><yellow>0</yellow>)

floor = <olive>Entity</olive>(<olive>model</olive>=<green>'quad'</green>, <olive>y</olive>=-.<yellow>5</yellow>, origin_<olive>y</olive>=.<yellow>5</yellow>, <olive>collider</olive>=<green>'box'</green>, <olive>scale</olive>=(<yellow>2</yellow>,<yellow>1</yellow><yellow>0</yellow>), <olive>visible</olive>=False)
ceiling = duplicate(floor, <olive>y</olive>=.<yellow>5</yellow>, rotation_<olive>z</olive>=<yellow>1</yellow><yellow>8</yellow><yellow>0</yellow>, <olive>visible</olive>=False)
left_wall = duplicate(floor, x=-.<yellow>5</yellow>*window.aspect_ratio, rotation_<olive>z</olive>=<yellow>9</yellow><yellow>0</yellow>, <olive>visible</olive>=True)
right_wall = duplicate(floor, x=.<yellow>5</yellow>*window.aspect_ratio, rotation_<olive>z</olive>=-<yellow>9</yellow><yellow>0</yellow>, <olive>visible</olive>=True)

<gray># Score variables</gray>
left_score = <yellow>0</yellow>
right_score = <yellow>0</yellow>
max_score = <yellow>5</yellow>
game_paused = False&nbsp;&nbsp;<gray># Added variable to track the game's paused state</gray>

collision_cooldown = .<yellow>1</yellow><yellow>5</yellow>
ball = <olive>Entity</olive>(<olive>model</olive>=<green>'circle'</green>, <olive>scale</olive>=.<yellow>0</yellow><yellow>5</yellow>, <olive>collider</olive>=<green>'box'</green>, speed=<yellow>0</yellow>, collision_cooldown=collision_cooldown)

<gray># Score text</gray>
score_text = Text(<olive>text</olive>=f"{left_score} : {right_score}", <olive>position</olive>=(<yellow>0</yellow>, .<yellow>4</yellow><yellow>5</yellow>), <olive>scale</olive>=<yellow>2</yellow>, <olive>origin</olive>=(<yellow>0</yellow>, <yellow>0</yellow>))

<purple>def</purple> update():
&nbsp;&nbsp;&nbsp;&nbsp;global left_score, right_score, game_paused

&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> game_paused:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp;<gray># Stop all updates <purple>if</purple> the game is paused</gray>

&nbsp;&nbsp;&nbsp;&nbsp;ball.collision_cooldown -= time.dt
&nbsp;&nbsp;&nbsp;&nbsp;ball.position += ball.right * time.dt * ball.speed

&nbsp;&nbsp;&nbsp;&nbsp;left_paddle.y += (held_keys[<green>'w'</green>] - held_keys[<green>'s'</green>]) * time.dt * <yellow>1</yellow>
&nbsp;&nbsp;&nbsp;&nbsp;right_paddle.y += (held_keys[<green>'up arrow'</green>] - held_keys[<green>'down arrow'</green>]) * time.dt * <yellow>1</yellow>

&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> ball.collision_cooldown &gt; <yellow>0</yellow>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

&nbsp;&nbsp;&nbsp;&nbsp;hit_info = ball.intersects()
&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> hit_info.hit:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.collision_cooldown = collision_cooldown

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> hit_info.entity in (left_paddle, right_paddle):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.rotation_z += <yellow>1</yellow><yellow>8</yellow><yellow>0</yellow> * (-<yellow>1</yellow> <purple>if</purple> hit_info.entity == left_paddle else <yellow>1</yellow>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.rotation_z -= (hit_info.entity.world_y - ball.y) * <yellow>2</yellow><yellow>0</yellow> * <yellow>3</yellow><yellow>2</yellow> * (-<yellow>1</yellow> <purple>if</purple> hit_info.entity == left_paddle else <yellow>1</yellow>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.speed *= <yellow>1</yellow>.<yellow>1</yellow>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<purple>elif</purple> hit_info.entity == right_wall:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left_score += <yellow>1</yellow>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_score()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<purple>elif</purple> hit_info.entity == left_wall:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;right_score += <yellow>1</yellow>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_score()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<gray># Particle effect on collision</gray>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;particle = <olive>Entity</olive>(<olive>model</olive>=<green>'quad'</green>, <olive>position</olive>=hit_info.world_point, <olive>scale</olive>=<yellow>0</yellow>, <olive>texture</olive>=<green>'circle'</green>, add_to_scene_entities=False)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;particle.animate_scale(.<yellow>2</yellow>, .<yellow>5</yellow>, <olive>curve</olive>=curve.out_expo)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;particle.animate_color(color.clear, duration=.<yellow>5</yellow>, <olive>curve</olive>=curve.out_expo)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;destroy(particle, dela<olive>y</olive>=.<yellow>5</yellow>)

&nbsp;&nbsp;&nbsp;&nbsp;<gray># Ball bounces off top and bottom of the screen</gray>
&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> ball.y &gt; ceiling.y - ball.scale_y/<yellow>2</yellow> or ball.y &lt; floor.y + ball.scale_y/<yellow>2</yellow>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.rotation_z = -ball.rotation_z&nbsp;&nbsp;<gray># Reverse vertical direction</gray>

<purple>def</purple> update_score():
&nbsp;&nbsp;&nbsp;&nbsp;global left_score, right_score, game_paused
&nbsp;&nbsp;&nbsp;&nbsp;score_text.text = f"{left_score} : {right_score}"

&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> left_score &gt;= max_score or right_score &gt;= max_score:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;winner_text = Text(f"{<green>'Left'</green> <purple>if</purple> left_score &gt;= max_score else <green>'Right'</green>} Player Wins!", <olive>y</olive>=<yellow>0</yellow>, <olive>scale</olive>=<yellow>2</yellow>, <olive>origin</olive>=(<yellow>0</yellow>, <yellow>0</yellow>))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ball.speed = <yellow>0</yellow>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;game_paused = True&nbsp;&nbsp;<gray># Pause the game after a win</gray>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke(destroy, winner_text, dela<olive>y</olive>=<yellow>3</yellow>)
&nbsp;&nbsp;&nbsp;&nbsp;<purple>else</purple>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reset()

<purple>def</purple> reset():
&nbsp;&nbsp;&nbsp;&nbsp;ball.position = (<yellow>0</yellow>, <yellow>0</yellow>, <yellow>0</yellow>)
&nbsp;&nbsp;&nbsp;&nbsp;ball.rotation = (<yellow>0</yellow>, <yellow>0</yellow>, <yellow>0</yellow>)
&nbsp;&nbsp;&nbsp;&nbsp;ball.speed = <yellow>1</yellow><yellow>0</yellow>
&nbsp;&nbsp;&nbsp;&nbsp;<purple>for</purple> paddle in (left_paddle, right_paddle):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paddle.collision = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paddle.y = <yellow>0</yellow>

info_text = Text("press space to play", <olive>y</olive>=-.<yellow>4</yellow><yellow>5</yellow>)

<purple>def</purple> input(key):
&nbsp;&nbsp;&nbsp;&nbsp;global game_paused

&nbsp;&nbsp;&nbsp;&nbsp;<purple>if</purple> key == <green>'space'</green> and <purple>not</purple> game_paused:&nbsp;&nbsp;<gray># Prevent restarting when the game is paused</gray>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info_text.enabled = False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reset()

app.run()

</code_block>
<script>
function copy_to_clipboard(containerid) {
    var range = document.createRange()
    range.selectNode(containerid)
    window.getSelection().removeAllRanges()
    window.getSelection().addRange(range)
    document.execCommand("copy")
    window.getSelection().removeAllRanges()
}
</script>
<br>
<br>
</body>
</html>